package classifiers;

import Utilities.Constants;
import data_structures.DiscreteHP;
import data_structures.HPConfiguration;
import data_structures.HyperParameter;
import weka.classifiers.Evaluation;
import weka.classifiers.lazy.IBk;
import weka.core.Instances;

/**
 * Implements K-nearest neighbor classifier using Weka's IBk classifier.
 * 
 */
public class KNNClassifier implements Classifier {

    private int lowerBound;
    private int upperBound;

    /**
     * @param lowerBound Lower bound for the k value
     * @param upperBound Upper bound for the k value
     */
    public KNNClassifier(int lowerBound, int upperBound) {
	this.lowerBound = lowerBound;
	this.upperBound = upperBound;
    }

    /**
     * Evaluate the classifier using 10-fold cross validation.
     */
    @Override
	public double evaluateClassifier(Instances instances, HPConfiguration conf) {
	HyperParameter k = conf.getHyperParameters()[0];
	IBk kNNClassifier = new IBk((int) k.getValue());

	try {
	    Evaluation eval = new Evaluation(instances);
	    eval.crossValidateModel(kNNClassifier, instances, 10,
				    Constants.RANDOM);
	    double accuracy = eval.pctCorrect();
	    return accuracy;
	} catch (Exception e) {
	    e.printStackTrace();
	}
	return -1;
    }

    @Override
	public HPConfiguration getHPConfiguration() {
	HyperParameter[] hyperParameters = new HyperParameter[1];
	hyperParameters[0] = new DiscreteHP(lowerBound, upperBound, lowerBound);
	return new HPConfiguration(hyperParameters);
    }

}
